package cn.shengchao.qywx.remote.rpc;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import cn.shengchao.examstar.rpc.base.PageResult;
import cn.shengchao.examstar.rpc.wecom.api.RuleDataServiceApi;
import cn.shengchao.examstar.rpc.wecom.req.RuleConditionGroupSaveDto;
import cn.shengchao.examstar.rpc.wecom.req.RuleConditionSaveDto;
import cn.shengchao.examstar.rpc.wecom.req.RuleDataPageQuery;
import cn.shengchao.examstar.rpc.wecom.req.RuleDataSaveDto;
import cn.shengchao.examstar.rpc.wecom.resp.RuleConditionGroupVo;
import cn.shengchao.examstar.rpc.wecom.resp.RuleConditionVo;
import cn.shengchao.examstar.rpc.wecom.resp.RuleDataVo;
import cn.shengchao.qywx.acl.IRuleDomainService;
import cn.shengchao.qywx.infrastrure.po.*;
import cn.shengchao.qywx.infrastrure.service.*;
import cn.shengchao.rule.base.ActionType;
import cn.shengchao.rule.condition.matchType.IMatchType;
import cn.shengchao.rule.condition.paramKey.IConditionParamKey;
import cn.shengchao.rule.engine.IRule;
import cn.shengchao.rule.engine.RuleElementContainer;
import cn.shengchao.rule.engine.RuleEngine;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import top.continew.starter.core.exception.BaseException;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;


@DubboService
public class RuleDataServiceDubboApi implements RuleDataServiceApi {
    @Autowired
    private QywxRuleMainService qywxRuleMainService;
    @Autowired
    private QywxRuleGroupService qywxRuleGroupService;
    @Autowired
    private QywxRuleConditionService qywxRuleConditionService;
    @Autowired
    private QywxSysCsGroupService qywxSysCsGroupService;
    @Autowired
    private QywxUserService qywxUserService;
    @Autowired
    private IRuleDomainService iRuleDomainService;

    @Override
    public PageResult<RuleDataVo> getRuleDataListForPage(RuleDataPageQuery query) {
        try
                (Page<Object> page = PageHelper.startPage(query.getPage(), query.getSize())) {
            List<QywxRuleMain> ruleMainList = qywxRuleMainService.selectRuleMainListForPage(query);
            List<RuleDataVo> list = fillRuleDataVo(ruleMainList);
            return PageResult.of(page.getTotal(), list);
        }

    }

    private List<RuleDataVo> fillRuleDataVo(List<QywxRuleMain> ruleMainList) {
        List<RuleDataVo> dataVoList = new ArrayList<>();
        if (CollUtil.isNotEmpty(ruleMainList)) {
            List<Long> ruleIds = ruleMainList.stream().map(QywxRuleMain::getId).toList();

            List<QywxRuleGroup> groupList = qywxRuleGroupService.list(Wrappers.lambdaQuery(QywxRuleGroup.class)
                    .in(QywxRuleGroup::getRuleId, ruleIds)
            );

            Map<Long, List<QywxRuleGroup>> groupMap = new HashMap<>();
            Map<Long, List<QywxRuleCondition>> conditionMap = new HashMap<>();

            if (CollUtil.isNotEmpty(groupList)) {
                List<QywxRuleCondition> conditionList = qywxRuleConditionService.list(Wrappers.lambdaQuery(QywxRuleCondition.class)
                        .in(QywxRuleCondition::getGroupId, groupList.stream().map(QywxRuleGroup::getId).toList())
                );
                groupMap = groupList.stream().collect(Collectors.groupingBy(QywxRuleGroup::getRuleId));
                conditionMap = conditionList.stream().collect(Collectors.groupingBy(QywxRuleCondition::getGroupId));
            }

            for (QywxRuleMain ruleMain : ruleMainList) {
                RuleDataVo dataVo = new RuleDataVo();
                dataVo.setId(ruleMain.getId());
                dataVo.setPriority(ruleMain.getPriority());
                dataVo.setValidEndTime(ruleMain.getValidEndTime());
                dataVo.setValidStartTime(ruleMain.getValidStartTime());
                dataVo.setRuleName(ruleMain.getRuleName());
                dataVo.setRuleState(ruleMain.getRuleStatus());
                dataVo.setLastUpdateTime(ruleMain.getLastUpdateTime());
                if (CollUtil.isNotEmpty(groupMap.get(ruleMain.getId()))) {
                    List<RuleConditionGroupVo> groupVoList = new ArrayList<>();
                    for (QywxRuleGroup group : groupMap.get(ruleMain.getId())) {
                        RuleConditionGroupVo groupVo = new RuleConditionGroupVo();
                        groupVo.setGroupId(group.getId());
                        groupVo.setActionType(group.getActionType());
                        groupVo.setActionValue(group.getActionValue());
                        ActionType actionType = ActionType.valueOf(group.getActionType());
                        if (actionType != null) {
                            switch (actionType) {
                                case CUSTOMER_GROUP:
                                    QywxSysCsGroup csGroup = qywxSysCsGroupService.getById(group.getActionValue());
                                    groupVo.setActionValueShow(csGroup == null ? "unknown" : csGroup.getCsGroupName());
                                    break;
                                case INVITER:
                                    groupVo.setActionValueShow("邀请所属");
                                    break;
                                case SPECIFIC_USER:
                                    List<QywxUser> qywxUserList = qywxUserService.list(Wrappers.lambdaQuery(QywxUser.class).eq(QywxUser::getUserId, group.getActionValue()));
                                    groupVo.setActionValueShow(CollUtil.isEmpty(qywxUserList) ? "unknown" : qywxUserList.getFirst().getName());
                                    break;
                                default:
                                    break;
                            }
                        }
                        groupVo.setRuleId(group.getRuleId());
                        List<RuleConditionVo> conditionVoList = new ArrayList<>();
                        if (CollUtil.isNotEmpty(conditionMap.get(group.getId()))) {
                            for (QywxRuleCondition condition : conditionMap.get(group.getId())) {
                                RuleConditionVo conditionVo = new RuleConditionVo();
                                conditionVo.setId(condition.getId());
                                conditionVo.setConditionType(condition.getConditionType());
                                IConditionParamKey paramKey = RuleElementContainer.getConditionParamKey(condition.getConditionParamKey());
                                conditionVo.setConditionParamName(paramKey.getParamShow());
                                conditionVo.setConditionParamKey(paramKey.getParamKey());
                                conditionVo.setValueTypeKey(paramKey.getValueTypeKey());
                                conditionVo.setMatchValue(condition.getMatchValue());
                                IMatchType matchType = RuleElementContainer.getMatchType(condition.getMatchTypeKey());
                                conditionVo.setMatchTypeKey(matchType.getMatchTypeKey());
                                conditionVo.setMatchTypeName(matchType.getMatchTypeValue());
                                conditionVoList.add(conditionVo);
                            }
                        }
                        groupVo.setConditionVoList(conditionVoList);
                        groupVoList.add(groupVo);
                    }
                    dataVo.setGroupVoList(groupVoList);
                }
                dataVoList.add(dataVo);
            }
        }
        return dataVoList;
    }

    @Transactional
    @Override
    public void copyRuleData(Long ruleId) {
        QywxRuleMain qywxRuleMain = qywxRuleMainService.getById(ruleId);
        List<QywxRuleGroup> qywxRuleGroups = qywxRuleGroupService.list(Wrappers.lambdaQuery(QywxRuleGroup.class)
                .eq(QywxRuleGroup::getRuleId, ruleId)
        );
        List<QywxRuleCondition> qywxRuleConditions = qywxRuleConditionService.list(Wrappers.lambdaQuery(QywxRuleCondition.class)
                .in(QywxRuleCondition::getGroupId, qywxRuleGroups.stream().map(QywxRuleGroup::getId).toList())
        );
        qywxRuleMain.setId(null);
        qywxRuleMain.setRuleStatus(0);
        qywxRuleMain.setLastUpdateTime(new Date());
        long maxRulePriority = qywxRuleMainService.selectRuleMaxPriority();
        // 规则优先级自增
        qywxRuleMain.setPriority((int) (maxRulePriority + 1));
        qywxRuleMain.setRuleName(qywxRuleMain.getRuleName() + "_copy" + RandomUtil.randomInt(1000, 9999));
        qywxRuleMainService.save(qywxRuleMain);
        if (CollUtil.isNotEmpty(qywxRuleGroups)) {
            Map<Long, List<QywxRuleCondition>> groupConditionMap =
                    qywxRuleConditions.stream().collect(Collectors.groupingBy(QywxRuleCondition::getGroupId));
            for (QywxRuleGroup qywxRuleGroup : qywxRuleGroups) {
                List<QywxRuleCondition> qywxRuleConditionsForGroup = groupConditionMap.get(qywxRuleGroup.getId());
                QywxRuleGroup qywxRuleGroupCopy = new QywxRuleGroup();
                BeanUtil.copyProperties(qywxRuleGroup, qywxRuleGroupCopy);
                qywxRuleGroupCopy.setId(null);
                qywxRuleGroupCopy.setRuleId(qywxRuleMain.getId());
                qywxRuleGroupService.save(qywxRuleGroupCopy);
                if (CollUtil.isNotEmpty(qywxRuleConditionsForGroup)) {
                    qywxRuleConditionsForGroup.forEach(qrc -> {
                        qrc.setId(null);
                        qrc.setGroupId(qywxRuleGroupCopy.getId());
                    });
                    qywxRuleConditionService.saveBatch(qywxRuleConditionsForGroup);
                }
            }
        }
    }

    @Transactional
    @Override
    public void saveRuleData(RuleDataSaveDto ruleDataSaveDto) {
        QywxRuleMain qywxRuleMain = new QywxRuleMain();
        long count = qywxRuleMainService.count(Wrappers.lambdaQuery(QywxRuleMain.class).eq(QywxRuleMain::getPriority, ruleDataSaveDto.getPriority()));
        //优先级冲突，设个最高优先级
        if (count > 0) {
            long maxRulePriority = qywxRuleMainService.selectRuleMaxPriority();
            // 规则优先级自增
            ruleDataSaveDto.setPriority((int) (maxRulePriority + 1));
        }
        if (qywxRuleMain.getId() != null) {
            qywxRuleMain = qywxRuleMainService.getById(ruleDataSaveDto.getId());
            qywxRuleMain.setRuleStatus(qywxRuleMain.getRuleStatus());
            //替代规则
            IRule rule = iRuleDomainService.fetchRuleById(qywxRuleMain.getId());
            RuleEngine.clearRule(rule);
        } else {
            qywxRuleMain = new QywxRuleMain();
            qywxRuleMain.setRuleStatus(0);

        }

        qywxRuleMain.setId(ruleDataSaveDto.getId());
        qywxRuleMain.setRuleName(ruleDataSaveDto.getRuleName());
        qywxRuleMain.setPriority(ruleDataSaveDto.getPriority());
        qywxRuleMain.setValidEndTime(ruleDataSaveDto.getValidEndTime());
        qywxRuleMain.setValidStartTime(ruleDataSaveDto.getValidStartTime());
        qywxRuleMain.setLastUpdateTime(new Date());
        qywxRuleMainService.saveOrUpdate(qywxRuleMain);
        Long ruleId = qywxRuleMain.getId();
        //数据层级深，先清理，后保存
        List<QywxRuleGroup> qywxRuleGroups = qywxRuleGroupService.list(Wrappers.lambdaQuery(QywxRuleGroup.class).eq(QywxRuleGroup::getRuleId, qywxRuleMain.getId()));
        if (CollUtil.isNotEmpty(qywxRuleGroups)) {
            List<QywxRuleCondition> qywxRuleConditions = qywxRuleConditionService.list(Wrappers.lambdaQuery(QywxRuleCondition.class).in(QywxRuleCondition::getGroupId, qywxRuleGroups.stream().map(QywxRuleGroup::getId).collect(Collectors.toList())));
            qywxRuleConditionService.removeByIds(qywxRuleConditions.stream().map(QywxRuleCondition::getId).collect(Collectors.toList()));
            qywxRuleGroupService.removeByIds(qywxRuleGroups.stream().map(QywxRuleGroup::getId).collect(Collectors.toList()));
        }
        if (CollUtil.isNotEmpty(ruleDataSaveDto.getGroupSaveDtoList())) {

            for (RuleConditionGroupSaveDto groupSaveDto : ruleDataSaveDto.getGroupSaveDtoList()) {
                QywxRuleGroup qywxRuleGroup = new QywxRuleGroup();

                qywxRuleGroup.setRuleId(qywxRuleMain.getId());
                qywxRuleGroup.setActionType(groupSaveDto.getActionType());
                qywxRuleGroup.setActionValue(groupSaveDto.getActionValue());
                qywxRuleGroup.setGroupProfit(0);
                qywxRuleGroupService.save(qywxRuleGroup);
                if (CollUtil.isNotEmpty(groupSaveDto.getConditioSaveDtoList())) {
                    for (RuleConditionSaveDto conditionSaveDto : groupSaveDto.getConditioSaveDtoList()) {
                        QywxRuleCondition qywxRuleCondition = new QywxRuleCondition();

                        IConditionParamKey iConditionParamKey = RuleElementContainer.getConditionParamKey(conditionSaveDto.getConditionParamKey());
                        qywxRuleCondition.setConditionParamKey(iConditionParamKey.getParamKey());
                        qywxRuleCondition.setValueTypeKey(iConditionParamKey.getValueTypeKey());
                        qywxRuleCondition.setConditionType(iConditionParamKey.getConditionType());
                        qywxRuleCondition.setMatchTypeKey(conditionSaveDto.getMatchTypeKey());
                        qywxRuleCondition.setGroupId(qywxRuleGroup.getId());
                        qywxRuleCondition.setMatchValue(conditionSaveDto.getMatchValue());
                        qywxRuleConditionService.save(qywxRuleCondition);
                    }
                }
            }
        }

    }

    @Transactional
    @Override
    public void changeRuleDataState(Long id, Integer state) {
        if (List.of(0, 1).contains(state)) {
            QywxRuleMain ruleMain = qywxRuleMainService.getById(id);
            if (ruleMain == null || ruleMain.getRuleStatus() >= 2) {
                throw new BaseException("规则数据没找到");
            } else {
                ruleMain.setRuleStatus(state);
                ruleMain.setLastUpdateTime(new Date());
                qywxRuleMainService.updateById(ruleMain);
                if (state == 1) {
                    //替代规则
                    IRule rule = iRuleDomainService.fetchRuleById(id);
                    RuleEngine.replaceRule(rule);
                } else {
                    IRule rule = iRuleDomainService.fetchRuleById(id);
                    RuleEngine.clearRule(rule);
                }
            }
        } else {
            throw new BaseException("状态值错误");
        }
    }

    @Transactional
    @Override
    public void deleteRuleData(Long id) {
        QywxRuleMain ruleMain = qywxRuleMainService.getById(id);
        LocalDateTime now = LocalDateTime.now();
        boolean isRuleActive = now.isAfter(LocalDateTimeUtil.of(ruleMain.getValidStartTime())) && now.isBefore(LocalDateTimeUtil.of(ruleMain.getValidEndTime()));
        if (isRuleActive && ruleMain.getRuleStatus() == 1) {
            throw new BaseException("规则处于生效状态，不能删除");
        }
        if (ruleMain.getRuleStatus() != 2) {
            ruleMain.setRuleStatus(2);
            ruleMain.setLastUpdateTime(new Date());
            qywxRuleMainService.updateById(ruleMain);
        }
    }
}
